/*
 * Copyright 2002-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory.support;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanCreationNotAllowedException;
import org.springframework.beans.factory.BeanCurrentlyInCreationException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.SingletonBeanRegistry;
import org.springframework.core.SimpleAliasRegistry;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * DefaultSingletonBeanRegistry类继承了SimpleAliasRegistry以及实现了SingletonBeanRegistry的接口。
 * 处理Bean的注册,销毁,以及依赖关系的注册和销毁。
 *
 * @author Juergen Hoeller
 * @see #registerSingleton
 * @see #registerDisposableBean
 * @see org.springframework.beans.factory.DisposableBean
 * @see org.springframework.beans.factory.config.ConfigurableBeanFactory
 * @since 2.0
 */
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

	/**
	 * 单例对象的缓存:从bean name到bean实例
	 * 一级缓存
	 */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/**
	 * 单例工厂的缓存:从bean name到ObjectFactory
	 * 三级缓存
	 */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/**
	 * 二级缓存
	 * <p>
	 * 存放的是【早期】的单例 bean 的映射。
	 * <p>
	 * 对应关系也是 bean name --> bean instance。
	 * <p>
	 * 它与 {@link #singletonObjects} 的区别区别在，于 earlySingletonObjects 中存放的 bean 不一定是完整的。
	 * <p>
	 * 从 {@link #getSingleton(String)} 方法中，中我们可以了解，bean 在创建过程中就已经加入到 earlySingletonObjects 中了，
	 * 所以当在 bean 的创建过程中就可以通过 getBean() 方法获取。
	 * 这个 Map 也是解决【循环依赖】的关键所在。
	 */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

	/**
	 * 一组已注册的单例，包含按注册顺序排列的bean name
	 */
	private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

	/**
	 * 正在创建中的单例 Bean 的名字的集合
	 */
	private final Set<String> singletonsCurrentlyInCreation =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));

	/**
	 * 当前不检查的bean的集合
	 */
	private final Set<String> inCreationCheckExclusions =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));

	/**
	 * 异常集合
	 */
	@Nullable
	private Set<Exception> suppressedExceptions;

	/**
	 * 当前是否在销毁bean中
	 */
	private boolean singletonsCurrentlyInDestruction = false;

	/**
	 * 一次性bean实例
	 */
	private final Map<String, Object> disposableBeans = new LinkedHashMap<>();

	/**
	 * 内部bean和外部bean之间关系
	 * Map between containing bean names: bean name to Set of bean names that the bean contains.
	 */
	private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);

	/**
	 * 指定bean与依赖指定bean的集合，比如b,c,d依赖a，那么就是key为a，---> b,c,d为value
	 * value 依赖 key
	 */
	private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

	/**
	 * 指定bean与指定bean依赖的集合，比如a依赖b，c，d，那么就是key为a，---> b，c，d为value
	 * key  依赖 value
	 */
	private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);


	@Override
	public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
		Assert.notNull(beanName, "Bean name must not be null");
		Assert.notNull(singletonObject, "Singleton object must not be null");
		synchronized (this.singletonObjects) {
			// 如果一缓存有，说明已经注册过
			Object oldObject = this.singletonObjects.get(beanName);
			if (oldObject != null) {
				throw new IllegalStateException("Could not register object [" + singletonObject +
						"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
			}
			// 没有缓存,开始注册
			addSingleton(beanName, singletonObject);
		}
	}

	/**
	 * 加入单例对象的缓存(一级缓存)
	 */
	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			// 加入单例对象缓存
			this.singletonObjects.put(beanName, singletonObject);
			// 移除单例工厂和早起的单例对象缓存
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			// 加入已注册bean
			this.registeredSingletons.add(beanName);
		}
	}

	/**
	 * 增加单例工厂的单例，取单例的时候调用getObject方法
	 */
	protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		synchronized (this.singletonObjects) {
			if (!this.singletonObjects.containsKey(beanName)) {
				// 放入三级缓存
				this.singletonFactories.put(beanName, singletonFactory);
				// 移除二级缓存
				this.earlySingletonObjects.remove(beanName);
				// 放入已注册的单例bean 中
				this.registeredSingletons.add(beanName);
			}
		}
	}

	@Override
	@Nullable
	public Object getSingleton(String beanName) {
		// 默认允许早期依赖
		return getSingleton(beanName, true);
	}

	/**
	 * 从缓存中获取beanName 对象
	 * 第一步，从 singletonObjects 中，获取 Bean 对象。
	 * 第二步，若为空且当前 bean 正在创建中，则从 earlySingletonObjects 中获取 Bean 对象。
	 * 第三步，若为空且允许提前创建，则从 singletonFactories 中获取相应的 ObjectFactory 对象。
	 * 若不为空，则调用其 ObjectFactory#getObject(String name) 方法，创建 Bean 对象，
	 * 然后将其加入到 earlySingletonObjects ，然后从 singletonFactories 删除。
	 * <p>
	 * 总体逻辑，就是根据 beanName 依次检测这三个 Map，若为空，从下一个，否则返回
	 */
	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 从一级缓存中获取,如果有直接返回
		Object singletonObject = this.singletonObjects.get(beanName);
		//缓存中的 bean 为空，且当前 bean 正在创建
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			// 加锁
			synchronized (this.singletonObjects) {
				// 从 earlySingletonObjects 获取
				singletonObject = this.earlySingletonObjects.get(beanName);
				// earlySingletonObjects 中没有，且允许提前创建
				if (singletonObject == null && allowEarlyReference) {
					//从三级缓存中获取
					// 从 singletonFactories 中获取对应的 ObjectFactory
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						// 获得 bean
						singletonObject = singletonFactory.getObject();
						// 添加 bean 到 earlySingletonObjects 中
						this.earlySingletonObjects.put(beanName, singletonObject);
						// 从 singletonFactories 中移除对应的 ObjectFactory
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		// 全局加锁
		synchronized (this.singletonObjects) {
			// <1> 从缓存中检查一遍
			// 因为 singleton 模式其实就是复用已经创建的 bean 所以这步骤必须检查
			Object singletonObject = this.singletonObjects.get(beanName);
			//  为空，开始加载过程
			if (singletonObject == null) {
				// 当前在销毁bean，不能创建
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
									"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
				// <2> 加载前置处理
				beforeSingletonCreation(beanName);
				// 记录是否为 新的 单例
				boolean newSingleton = false;
				// 如果当前没有异常，初始化异常集合
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// <3> 初始化 bean
					// 通过ObjectFactory的getObject创建bean，实际是回调AbstractAutowireCapableBeanFactory.createBean()方法
					singletonObject = singletonFactory.getObject();
					// 标记为新的单例
					newSingleton = true;
				} catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					// 有可能是其他方式创建的bean (从一级缓存中获取,如果为空抛出异常)
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				} catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				} finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					// <4> 后置处理
					afterSingletonCreation(beanName);
				}
				// 是新创建的bean，就加入到缓存中并移除其他缓存，如果是其他方式创建的bean，说明已经加入过缓存了，这边不再加入
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

	/**
	 * 注册过程中发生的异常，加入到异常集合
	 */
	protected void onSuppressedException(Exception ex) {
		synchronized (this.singletonObjects) {
			if (this.suppressedExceptions != null) {
				this.suppressedExceptions.add(ex);
			}
		}
	}

	/**
	 * 移除单例，这四个同时移除
	 */
	protected void removeSingleton(String beanName) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.remove(beanName);
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.remove(beanName);
		}
	}

	@Override
	public boolean containsSingleton(String beanName) {
		// 用一级缓存来判断
		return this.singletonObjects.containsKey(beanName);
	}

	@Override
	public String[] getSingletonNames( ) {
		//获取已经注册过的bean
		synchronized (this.singletonObjects) {
			return StringUtils.toStringArray(this.registeredSingletons);
		}
	}

	@Override
	public int getSingletonCount( ) {
		// 获取单例的个数
		synchronized (this.singletonObjects) {
			return this.registeredSingletons.size();
		}
	}


	/**
	 * 设置不检查的beanName
	 */
	public void setCurrentlyInCreation(String beanName, boolean inCreation) {
		Assert.notNull(beanName, "Bean name must not be null");
		if (!inCreation) {
			this.inCreationCheckExclusions.add(beanName);
		} else {
			this.inCreationCheckExclusions.remove(beanName);
		}
	}

	public boolean isCurrentlyInCreation(String beanName) {
		Assert.notNull(beanName, "Bean name must not be null");
		// 如果这个beanName在不检查集合里，返回false，说明当前没有创建
		// 如果这个beanName要检查，那就要返回是否是正在创建的bean
		return (!this.inCreationCheckExclusions.contains(beanName) && isActuallyInCreation(beanName));
	}

	protected boolean isActuallyInCreation(String beanName) {
		return isSingletonCurrentlyInCreation(beanName);
	}

	/**
	 * 该方法用于判断该 beanName 对应的 Bean 是否在创建过程中
	 */
	public boolean isSingletonCurrentlyInCreation(String beanName) {
		return this.singletonsCurrentlyInCreation.contains(beanName);
	}

	/**
	 * bean 创建之前的回调
	 * 用于添加标志，当前 bean 正处于创建中
	 */
	protected void beforeSingletonCreation(String beanName) {
		// 如果这个beanName要检查，看看add的时候返回什么，如果返回false，说明已经在创建了，抛异常
		if (!this.inCreationCheckExclusions.contains(beanName)
				// 添加
				&& !this.singletonsCurrentlyInCreation.add(beanName)) {
			// 如果添加失败，则抛出 BeanCurrentlyInCreationException 异常。
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

	/**
	 * 创建之后的回调
	 * 用于移除标记，当前 Bean 不处于创建中。
	 */
	protected void afterSingletonCreation(String beanName) {
		// 如果这个beanName要检查，看看remove返回什么，如果返回false，说明已经创建完了。
		if (!this.inCreationCheckExclusions.contains(beanName)
				// 移除
				&& !this.singletonsCurrentlyInCreation.remove(beanName)) {
			// 如果移除失败，则抛出 IllegalStateException 异常
			throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
		}
	}


	/**
	 * 注册一次性bean实例
	 */
	public void registerDisposableBean(String beanName, DisposableBean bean) {
		synchronized (this.disposableBeans) {
			this.disposableBeans.put(beanName, bean);
		}
	}

	/**
	 * Register a containment relationship between two beans,
	 * e.g. between an inner bean and its containing outer bean.
	 * <p>Also registers the containing bean as dependent on the contained bean
	 * in terms of destruction order.
	 *
	 * @param containedBeanName  the name of the contained (inner) bean
	 * @param containingBeanName the name of the containing (outer) bean
	 * @see #registerDependentBean
	 */
	public void registerContainedBean(String containedBeanName, String containingBeanName) {
		synchronized (this.containedBeanMap) {
			// 如果没有key为containingBeanName的value，说明内部bean集合为空，则初始化一个
			Set<String> containedBeans =
					this.containedBeanMap.computeIfAbsent(containingBeanName, k -> new LinkedHashSet<>(8));
			// 如果已经存在了对应关系，则直接返回，不存在，就添加对应关系
			if (!containedBeans.add(containedBeanName)) {
				return;
			}
		}
		// 注册依赖bean
		registerDependentBean(containedBeanName, containingBeanName);
	}

	/**
	 * Register a dependent bean for the given bean,
	 * to be destroyed before the given bean is destroyed.
	 *
	 * @param beanName          the name of the bean
	 * @param dependentBeanName the name of the dependent bean
	 */
	public void registerDependentBean(String beanName, String dependentBeanName) {
		// 获取 beanName
		String canonicalName = canonicalName(beanName);

		// 添加 <canonicalName, <dependentBeanName>> 到 dependentBeanMap 中
		synchronized (this.dependentBeanMap) {
			Set<String> dependentBeans =
					this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
			// 如果已经存在了对应关系，则直接返回,不存在，就添加对应关系
			if (!dependentBeans.add(dependentBeanName)) {
				return;
			}
		}

		// 添加 <dependentBeanName, <canonicalName>> 到 dependenciesForBeanMap 中
		synchronized (this.dependenciesForBeanMap) {
			Set<String> dependenciesForBean =
					this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
			// 添加对应关系
			dependenciesForBean.add(canonicalName);
		}
	}

	/**
	 * dependentBeanName是否依赖beanName
	 */
	protected boolean isDependent(String beanName, String dependentBeanName) {
		synchronized (this.dependentBeanMap) {
			return isDependent(beanName, dependentBeanName, null);
		}
	}

	private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
		// alreadySeen 已经检测的依赖 bean
		if (alreadySeen != null && alreadySeen.contains(beanName)) {
			return false;
		}
		// 获取原始 beanName
		String canonicalName = canonicalName(beanName);
		// 获取当前 beanName 的依赖集合
		Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
		// 为空，说明没有bean依赖beanName，直接返回false
		if (dependentBeans == null) {
			return false;
		}
		// 有其他bean依赖beanName，且包含了dependentBeanName，返回true
		// 存在，则证明存在已经注册的依赖
		if (dependentBeans.contains(dependentBeanName)) {
			return true;
		}
		// 有其他bean依赖beanName，但是不包含dependentBeanName
		// 递归检测依赖
		for (String transitiveDependency : dependentBeans) {
			if (alreadySeen == null) {
				alreadySeen = new HashSet<>();
			}
			alreadySeen.add(beanName);
			// 递推
			if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 是否有其他对象依赖指定bean
	 */
	protected boolean hasDependentBean(String beanName) {
		return this.dependentBeanMap.containsKey(beanName);
	}

	/**
	 * 返回依赖指定bean的数组
	 */
	public String[] getDependentBeans(String beanName) {
		Set<String> dependentBeans = this.dependentBeanMap.get(beanName);
		if (dependentBeans == null) {
			return new String[0];
		}
		synchronized (this.dependentBeanMap) {
			return StringUtils.toStringArray(dependentBeans);
		}
	}

	/**
	 * Return the names of all beans that the specified bean depends on, if any.
	 *
	 * @param beanName the name of the bean
	 * @return the array of names of beans which the bean depends on,
	 * or an empty array if none
	 */
	public String[] getDependenciesForBean(String beanName) {
		Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(beanName);
		if (dependenciesForBean == null) {
			return new String[0];
		}
		synchronized (this.dependenciesForBeanMap) {
			return StringUtils.toStringArray(dependenciesForBean);
		}
	}

	public void destroySingletons( ) {
		if (logger.isTraceEnabled()) {
			logger.trace("Destroying singletons in " + this);
		}
		// 设置当前正在销毁
		synchronized (this.singletonObjects) {
			this.singletonsCurrentlyInDestruction = true;
		}

		String[] disposableBeanNames;
		synchronized (this.disposableBeans) {
			disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
		}
		// 销毁disposableBeans中的所有bean
		for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
			destroySingleton(disposableBeanNames[i]);
		}
		// 清空containedBeanMap、dependentBeanMap、dependenciesForBeanMap
		this.containedBeanMap.clear();
		this.dependentBeanMap.clear();
		this.dependenciesForBeanMap.clear();

		// 清除单例缓存
		clearSingletonCache();
	}

	/**
	 * 清除单例缓存
	 */
	protected void clearSingletonCache( ) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.clear();
			this.singletonFactories.clear();
			this.earlySingletonObjects.clear();
			this.registeredSingletons.clear();
			this.singletonsCurrentlyInDestruction = false;
		}
	}

	/**
	 * 销毁单例bean
	 */
	public void destroySingleton(String beanName) {
		// 从缓存中移除
		removeSingleton(beanName);

		// Destroy the corresponding DisposableBean instance.
		DisposableBean disposableBean;
		synchronized (this.disposableBeans) {
			// 从disposableBeans移除，如果有beanName对应的对象，返回这个对象
			disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
		}
		// 销毁bean
		destroyBean(beanName, disposableBean);
	}

	/**
	 * 销毁bean
	 * 如果销毁A 要先销毁依赖A的 B C
	 */
	protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
		// Trigger destruction of dependent beans first...
		Set<String> dependencies;
		synchronized (this.dependentBeanMap) {
			// Within full synchronization in order to guarantee a disconnected Set
			// 获取依赖当前beanName的bean
			dependencies = this.dependentBeanMap.remove(beanName);
		}
		if (dependencies != null) {
			if (logger.isTraceEnabled()) {
				logger.trace("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);
			}
			// 移除依赖当前beanName的bean
			for (String dependentBeanName : dependencies) {
				destroySingleton(dependentBeanName);
			}
		}

		// Actually destroy the bean now...
		if (bean != null) {
			try {
				bean.destroy();
			} catch (Throwable ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", ex);
				}
			}
		}

		// Trigger destruction of contained beans...
		// 异常beanName的对应关系的bean
		Set<String> containedBeans;
		synchronized (this.containedBeanMap) {
			// Within full synchronization in order to guarantee a disconnected Set
			containedBeans = this.containedBeanMap.remove(beanName);
		}
		if (containedBeans != null) {
			for (String containedBeanName : containedBeans) {
				destroySingleton(containedBeanName);
			}
		}

		// Remove destroyed bean from other beans' dependencies.
		// 这个对象被其他bean依赖，也要移除依赖关系
		synchronized (this.dependentBeanMap) {
			for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext(); ) {
				Map.Entry<String, Set<String>> entry = it.next();
				Set<String> dependenciesToClean = entry.getValue();
				dependenciesToClean.remove(beanName);
				//如果除了当前的beanName，没有其他依赖了，直接删除
				if (dependenciesToClean.isEmpty()) {
					it.remove();
				}
			}
		}

		// Remove destroyed bean's prepared dependency information.
		this.dependenciesForBeanMap.remove(beanName);
	}

	/**
	 * 用于加锁操作，返回singletonObjects，通过方法暴露这个对象。
	 */
	@Override
	public final Object getSingletonMutex( ) {
		return this.singletonObjects;
	}

}
